<?php

namespace Yolo\Config;

use Yolo\Errors\ConfigInvalidException;
use Yolo\Utils\Console;

/**
 * Class Config
 * @author <LUSHAOMING> <lushaoming6@gmail.com>
 * @date 2024-12-09
 */
class Config
{
    private string $baseDir;

    private array $config = [];

    public function __construct(string $baseDir)
    {
        $this->baseDir = realpath($baseDir);

        $this->init();
    }

    /**
     * 初始化配置文件
     * @return void
     * @throws ConfigInvalidException if config file not found
     */
    private function init(): void
    {
        Console::log("Loading config file: $this->baseDir/config.php");

        if (!file_exists($this->baseDir . '/config.php')) {
            throw new ConfigInvalidException('Config file not found');
        }

        $config = include $this->baseDir . '/config.php';

        $this->config = $this->extendsConfig($config);
    }

    /**
     * 解析通过extends拓展的配置文件
     * @param array $config
     * @return array
     * @throws ConfigInvalidException if config file not found
     */
    private function extendsConfig(array $config): array
    {
        if (!isset($config['$[[extends]]'])) {
            return $config;
        }

        if (!file_exists($config['$[[extends]]'])) {
            throw new ConfigInvalidException('Config file not found');
        }

        if (is_string($config['$[[extends]]'])) {
            $extends = include $config['$[[extends]]'];

            $config = $this->mergeConfig($config, $extends);
        } elseif (is_array($config['$[[extends]]'])) {

            $extendsFiles = $config['$[[extends]]'];
            foreach ($extendsFiles as $extendFile) {
                $extendConfig = include $extendFile;
                $config = $this->mergeConfig($config, $extendConfig);
            }
        }

        unset($config['$[[extends]]']);

        return $config;
    }

    /**
     * 合并配置文件
     * @param array $config
     * @param array $extendsConfig
     * @return array
     */
    private function mergeConfig(array $config, array $extendsConfig): array
    {
        foreach ($extendsConfig as $key => $value) {

            if (is_array($value)) {

                if (!isset($config[$key])) {
                    $config[$key] = [];
                }

                $config[$key] = $this->mergeConfig($config[$key], $value);
            } else {

                if (!isset($config[$key])) {
                    $config[$key] = $value;
                }
            }
        }

        return $config;
    }

    /**
     * Get config value by key
     * @param string $key
     * @param mixed|null $default
     * @return mixed|null
     */
    public function get(string $key, mixed $default = null): mixed
    {
        if (!$key) {
            return $this->config;
        }

        $keys = explode('.', $key);

        $config = $this->config;

        foreach ($keys as $key) {

            if (!isset($config[$key])) {
                return $default;
            }

            $config = $config[$key];
        }

        return $config;
    }

    /**
     * Get client connection
     * @param string $serviceName
     * @return string
     */
    public function getClientConnection(string $serviceName): string
    {
        return $this->get("rpc.client.connections.$serviceName") ?? '';
    }

    /**
     * Get instance id
     * @return string
     */
    public function getInstanceId(): string
    {
        return $this->get('application.instanceId') ?? '';
    }
}
